package com.meizu.utils;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 封装JDBC，通过简单的方法调用，就能实现数据库的操作
 * 1、一个字符串（指定context.xml连接池配置文件中的name）
 * 2、四大对象（数据源对象，连接对象、预编译执行对象、结果集对象）
 * 4、静态块加载数据源对象
 * 5、[方法]获取连接对象
 * 6、[方法]查询方法query(String sql,Object..param,RowMapper<T> map):List<T>
 * 7、[方法]增删改方法update(String sql,Object..param):Integer
 * 8、[方法]关闭所有资源closeAll():void
 */
public class SQLHelper{
    private final static String CONTEXT_NAME="jdbc/meizu";
    //    2，三个变量(连接对象[矿道],预编译执行对象[工具]，结果集对象[卡车])
    private static DataSource ds;
    private Connection conn;
    private PreparedStatement stmt;
    private ResultSet rs;

    //    3，一个静态块(数据源对象)
    static {
        try {
            Context ctx = new InitialContext();
            ds = (DataSource)ctx.lookup("java:comp/env/"+CONTEXT_NAME);
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    //4，获取连接对象getConnection
    private Connection getConnection() {
        try {
            if (conn == null || conn.isClosed()) {
                conn=ds.getConnection();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    //5，关闭所有对象colseAll
    private void colseAll() {
//        关闭原则，先创建的后关闭
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    6，执行增删改的方法update(SQL语句，参数列表)
    @param sql  增删改语句
    @param params  不定长参数(有几个占位符？,就有几个参数)
    @return 受影响的行数，返回-1表示异常，其他正常
     */
    public Integer update(String sql, Object... params) {
        //①创建执行对象
        try {
            stmt = getConnection().prepareStatement(sql);
            //②绑定参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //③执行增删改操作
            Integer r = stmt.executeUpdate();
            System.out.println("增删改的语句是" + stmt);
            return r;
        } catch (SQLException e) {
            e.printStackTrace();
//            抛出异常，返回-1
            return -1;
        } finally {
            //④关闭资源
            colseAll();
        }
    }

    /*
    7,执行查询方法，query(SQL语句，RowMapper接口实现类，参数列表)
    @param sql 查询sql语句
    @param rowmap RowMapper接口实现类
    @param param 不定长参数
    @return 查询到的数据集合
     */
    public <T> List<T> query(String sql, RowMapper<T> rowmap, Object... params) {
        try {
            //①创建执行对象
            stmt = getConnection().prepareStatement(sql);
            //②绑定参数、有几个问号，就需要绑定参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //③执行查询操作
            rs = stmt.executeQuery();
            System.out.println("查询语句是" + stmt);
            List<T> list = null;
            if (rs != null) {
                list = new ArrayList<T>();
                //④遍历rs结果集，获取一行一行的数据
                while(rs.next()) {
                    //并通过RowMapper接口，将数据转换成JAVA对象
                    T t = rowmap.map(rs);
//                酱JAVA对象添加到集合中
                    list.add(t);
                }
            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
            //抛出异常，返回空
            return null;
        }finally {
            //⑤关闭资源
            colseAll();
        }
    }

    /**
     * 8、执行查询操作，最多返回一条记录
     * @param sql  查询语句
     * @param rowmap RowMapper接口实现类
     * @param params  不定长参数
     * @return  返回查询的单条记录
     */
    public <T> T one(String sql, RowMapper<T> rowmap, Object...params){
        List<T> list = query(sql,rowmap,params);
        if(list!=null && list.size()>0){
            return list.get(0);
        }
        return null;
    }

    /*
    9，专门用来执行新增操作，返回值是新增的主键编号（适用于主键自增auto_increment情况）
    @param sql  新增操作
    @param params  不定长参数(有几个占位符？,就有几个参数)
    @return 新增的主键编号
     */
    public Integer insert(String sql, Object... params) {
        //①创建执行对象
        try {
            stmt = getConnection().prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            //②绑定参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //③执行新增操作
            Integer r = stmt.executeUpdate();
            System.out.println("执行的新增语句是" + stmt);
            ResultSet rs = stmt.getGeneratedKeys();//获取新增的主键，存储在结果集中
            if(rs!=null && rs.next()){
                return rs.getInt(1);
            }
            return 0;
        } catch (SQLException e) {
            e.printStackTrace();
//            抛出异常，返回-1
            return -1;
        } finally {
            //④关闭资源
            colseAll();
        }
    }
}
